﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using System.Threading;

namespace Xceed.Silverlight.Data
{
  internal class FullySyncAsyncEnumerator<T> : AsyncParentEnumerator<T>
  {
    #region Static Fields

    private static readonly TimeSpan WaitTimeOut = TimeSpan.FromSeconds( 1 );

    private static readonly Guid CountCallId = DataUtils.CreateCallId();
    private static readonly Guid JumpMoveAndFetchCallId = DataUtils.CreateCallId();
    private static readonly Guid GroupCountCallId = DataUtils.CreateCallId();
    private static readonly Guid GetStatValuesCallId = DataUtils.CreateCallId();

    #endregion

    #region Constructor

    internal FullySyncAsyncEnumerator( IAsyncEnumerator childEnumerator )
      : base( childEnumerator )
    {
    }

    #endregion

    #region IsFullySynchronized Property

    public sealed override bool IsFullySynchronized
    {
      get
      {
        return true;
      }
    }

    #endregion

    public override IAsyncResult BeginCount( CountParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      AsyncResult asyncResult = new AsyncResult( FullySyncAsyncEnumerator<T>.CountCallId, userCallback, asyncState );
      IAsyncResult childAsyncResult = base.BeginCount( parameters, null, null );

      if( this.Wait( childAsyncResult ) )
      {
        asyncResult.StartSync( base.EndCount( childAsyncResult ) );
      }

      return asyncResult;
    }

    public override CountResult EndCount( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( FullySyncAsyncEnumerator<T>.CountCallId );

      return asyncResult.GetCallResult<CountResult>();
    }

    public override JumpMoveAndFetchAsyncResult BeginJumpMoveAndFetch( JumpMoveAndFetchParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      JumpMoveAndFetchAsyncResult asyncResult = new JumpMoveAndFetchAsyncResult( FullySyncAsyncEnumerator<T>.JumpMoveAndFetchCallId, userCallback, asyncState, parameters );
      JumpMoveAndFetchAsyncResult childAsyncResult = base.BeginJumpMoveAndFetch( parameters, null, null );

      if( this.Wait( childAsyncResult ) )
      {
        asyncResult.StartSync( base.EndJumpMoveAndFetch( childAsyncResult ) );
      }

      return asyncResult;
    }

    public override JumpMoveAndFetchResult<T> EndJumpMoveAndFetch( JumpMoveAndFetchAsyncResult jumpMoveAndFetchAsyncResult )
    {
      jumpMoveAndFetchAsyncResult.ValidateCallEnd( FullySyncAsyncEnumerator<T>.JumpMoveAndFetchCallId );

      return jumpMoveAndFetchAsyncResult.GetCallResult<JumpMoveAndFetchResult<T>>();
    }

    public override IAsyncResult BeginGroupCount( CountParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      AsyncResult asyncResult = new AsyncResult( FullySyncAsyncEnumerator<T>.GroupCountCallId, userCallback, asyncState );
      IAsyncResult childAsyncResult = base.BeginGroupCount( parameters, null, null );

      if( this.Wait( childAsyncResult ) )
      {
        asyncResult.StartSync( base.EndGroupCount( childAsyncResult ) );
      }

      return asyncResult;
    }

    public override GroupCountResult EndGroupCount( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( FullySyncAsyncEnumerator<T>.GroupCountCallId );

      return asyncResult.GetCallResult<GroupCountResult>();
    }

    public override IAsyncResult BeginGetStatValues( StatParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      AsyncResult asyncResult = new AsyncResult( FullySyncAsyncEnumerator<T>.GetStatValuesCallId, userCallback, asyncState );
      IAsyncResult childAsyncResult = base.BeginGetStatValues( parameters, null, null );

      if( this.Wait( childAsyncResult ) )
      {
        asyncResult.StartSync( base.EndGetStatValues( childAsyncResult ) );
      }

      return asyncResult;
    }

    public override StatResults EndGetStatValues( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( FullySyncAsyncEnumerator<T>.GetStatValuesCallId );

      return asyncResult.GetCallResult<StatResults>();
    }

    protected override void Dispose( bool disposing )
    {
      m_disposed = true;

      base.Dispose( disposing );
    }

    private bool Wait( IAsyncResult asyncResult )
    {
      WaitHandle waitHandle = asyncResult.AsyncWaitHandle;

      while( !waitHandle.WaitOne( FullySyncAsyncEnumerator<T>.WaitTimeOut ) )
      {
        if( m_disposed )
          return false;
      }

      return true;
    }

    #region Private Fields

    private bool m_disposed; //false

    #endregion
  }
}
